matrix g_mWorld : MATWORLD;
matrix g_mWorldViewProjection:MATWORLDVIEWPROJECTION;
matrix g_mWorldInverseTranspose:MATWORLDINVERSETRANSPOSE;
bool g_bLightEnable : BOOL0;
float4 g_mtrlAmbient : AMBIENT;
float4 g_mtrlDiffuse : DIFFUSE;
float4 g_colorVertex : FLOATARRAY0;
texture g_Tex0 : TEXTURE0;

struct LIGHTPROPERTY{
	float4 Diffuse;
	float4 Ambient;
	float4 Specular;
	float3 vPosition;
	float3 vDirection;
	float Range;
	float Falloff;
	float Attenuation0;
	float Attenuation1;
	float Attenuation2;
	float Theta;
	float Phi;
};
float g_PointLightNum : POINTLIGHTNUM;
float g_DirLightNum : DIRLIGHTNUM;
float g_SpotLightNum : SPOTLIGHTNUM;
LIGHTPROPERTY g_Light[12] : LIGHTPROPERTY;

sampler g_S0 = sampler_state{
	Texture = <g_Tex0>;
	MagFilter = Linear;
	MinFilter = Linear;
	MipFilter = Point;
	MipMapLodBias = -2;
};

struct OUTVS{
	float4 vPosition : POSITION0;
	float2 vTexcoord : TEXCOORD0;
	float3 vNormalWorld : TEXCOORD1;
	float3 vPositionWorld : TEXCOORD2;
};

OUTVS MainVS(
	float3 vInPosition : POSITION0,
	float3 vInNormal : NORMAL0,
	float2 vInTexcoord : TEXCOORD0){
	OUTVS o = (OUTVS)0;
	o.vPositionWorld = mul(float4(vInPosition,1.0f),g_mWorld).xyz;
	o.vPosition = mul(float4(vInPosition,1.0f),g_mWorldViewProjection);
	o.vNormalWorld = normalize(mul(float4(vInNormal,0.0f),g_mWorldInverseTranspose).xyz);
	o.vTexcoord = vInTexcoord;
	return o;
}

struct INPUTPS{
	float2 vTexcoord : TEXCOORD0;
	float3 vNormalWorld : TEXCOORD1;
	float3 vPositionWorld : TEXCOORD2;
};

float4 MainPS(INPUTPS i) : COLOR{
	float4 Color = tex2D(g_S0,i.vTexcoord)*g_mtrlDiffuse+g_mtrlAmbient;
	if (g_bLightEnable){
		float4 ResultColor = 0;
		i.vNormalWorld = normalize(i.vNormalWorld);
		int index = 0;
		float l = 0, atten=0, d=0, spot=0, cosalpha=0;
		float3 LightToPos = 0;
		int NumLights = g_PointLightNum+g_DirLightNum+g_SpotLightNum;
		for (int j=0; j<g_PointLightNum; j++){
			index = j;
			LightToPos = i.vPositionWorld-g_Light[index].vPosition;
			d = length(LightToPos);
			if (d<g_Light[index].Range){
				l = saturate(dot(i.vNormalWorld,-normalize(LightToPos)));
				atten = g_Light[index].Attenuation0+g_Light[index].Attenuation1*d+g_Light[index].Attenuation2*d*d;
				ResultColor += Color*l/atten+Color*g_Light[index].Ambient;
			}
		}
		for (int j=0; j<g_DirLightNum; j++){
			index = j+g_PointLightNum;
			l = saturate(dot(i.vNormalWorld,-g_Light[index].vDirection));
			ResultColor += Color*l+Color*g_Light[index].Ambient;
		}
		for (int j=0; j<g_SpotLightNum; j++){
			index = j+g_PointLightNum+g_DirLightNum;
			LightToPos = i.vPositionWorld-g_Light[index].vPosition;
			d = length(LightToPos);
			if (d<g_Light[index].Range){
				LightToPos = normalize(LightToPos);
				cosalpha = dot(LightToPos,g_Light[index].vDirection);
				
				atten = g_Light[index].Attenuation0+g_Light[index].Attenuation1*d+g_Light[index].Attenuation2*d*d;
				l = saturate(dot(i.vNormalWorld,-g_Light[index].vDirection));
				float cosphi = cos(g_Light[index].Phi/2);
				float costheta = cos(g_Light[index].Theta/2);
				spot = pow(saturate((cosalpha-cosphi)/(costheta-cosphi)),g_Light[index].Falloff);
				
				ResultColor += Color*(g_Light[index].Diffuse*l/atten*spot+g_Light[index].Ambient);
			}
		}
		return ResultColor;
	}else{
		return Color;
	}
}

float4 VertexModePS() : COLOR{
	return g_colorVertex;
}

float4 WirePS() : COLOR{
	return float4(0,1,0,0);
}

technique Tech0{
	pass P0{
			vertexShader = compile vs_2_0 MainVS();
			pixelShader = compile ps_3_0 MainPS();
		}
}

technique TechVertexMode{
	pass P0{
		vertexShader = compile vs_2_0 MainVS();
		pixelShader = compile ps_2_0 VertexModePS();
		DepthBias = -0.001f;
		ZWriteEnable = False;
	}
}

technique TechWireframe{
	pass P0{
		vertexShader = compile vs_2_0 MainVS();
		pixelShader = compile ps_2_0 WirePS();
		DepthBias = -0.00001f;
		CullMode = None;
		FillMode = Wireframe;
	}
}

technique TechFace{
	pass P0{
		vertexShader = compile vs_2_0 MainVS();
		pixelShader = compile ps_2_0 VertexModePS();
		DepthBias = -0.000005f;
	}
}
